using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using HadronData;

namespace Hadron.Entities
{
    enum EntityStatus
    {
        Waiting,
        Active,
        Destroyed,
        Deactivated
    }

    abstract class Entity
    {
        protected static Random s_random = new Random();

        protected EntityMarker m_entityMarker;
        protected Environment m_environment;
        protected Transformation m_trnPlacement;
        protected Vector2 m_vecVelocity;
        protected int m_nHealth, m_nPoints;
        protected EntityStatus m_entityStatus;
        protected Circle m_circleBounds;

        public static Entity Create(EntityMarker p_entityMarker, Environment p_environment)
        {
            Entity enemy = null;
            switch (p_entityMarker.EntityType)
            {
                case EntityType.Gravity:
                    enemy = new Gravity(p_entityMarker, p_environment);
                    break;
                case EntityType.FuelStation:
                    enemy = new Station(p_entityMarker, p_environment, StationType.Fuel);
                    break;
                case EntityType.RepairStation:
                    enemy = new Station(p_entityMarker, p_environment, StationType.Repair);
                    break;
                case EntityType.CargoStation:
                    enemy = new Station(p_entityMarker, p_environment, StationType.Cargo);
                    break;
                case EntityType.Crate:
                    enemy = new Crate(p_entityMarker, p_environment);
                    break;
                case EntityType.Scientist:
                    enemy = new Scientist(p_entityMarker, p_environment);
                    break;
                case EntityType.Drone:
                    enemy = new Drone(p_entityMarker, p_environment);
                    break;
                case EntityType.GunFighter:
                    enemy = new Fighter(p_entityMarker, p_environment, false);
                    break;
                case EntityType.MissileFighter:
                    enemy = new Fighter(p_entityMarker, p_environment, true);
                    break;
                case EntityType.GunTurret:
                    enemy = new Turret(p_entityMarker, p_environment, false);
                    break;
                case EntityType.MissileTurret:
                    enemy = new Turret(p_entityMarker, p_environment, true);
                    break;
                case EntityType.Vent:
                    enemy = new Vent(p_entityMarker, p_environment);
                    break;
                case EntityType.Switch:
                    enemy = new Switch(p_entityMarker, p_environment);
                    break;
                case EntityType.SwitchGate:
                    enemy = new Gate(p_entityMarker, p_environment, false);
                    break;
                case EntityType.TimedGate:
                    enemy = new Gate(p_entityMarker, p_environment, true);
                    break;
                case EntityType.Attractor:
                    enemy = new GravityDevice(p_entityMarker, p_environment, true);
                    break;
                case EntityType.Repulsor:
                    enemy = new GravityDevice(p_entityMarker, p_environment, false);
                    break;
                case EntityType.Reactor:
                    enemy = new Reactor(p_entityMarker, p_environment);
                    break;
                case EntityType.EntryPortal:
                    enemy = new Portal(p_entityMarker, p_environment, false);
                    break;
                case EntityType.ExitPortal:
                    enemy = new Portal(p_entityMarker, p_environment, true);
                    break;
                default:
                    return null;
            }
            enemy.Placement = p_entityMarker.Placement;

            if (enemy is LandEntity)
                ((LandEntity) enemy).FindAnchor();

            return enemy;
        }

        public Entity(EntityMarker p_entityMarker, Environment p_environment)
        {
            m_entityMarker = p_entityMarker;
            m_environment = p_environment;
            m_trnPlacement = m_entityMarker.Placement;
            m_vecVelocity = Vector2.Zero;
            m_nHealth = 1;
            m_nPoints = 100;
            m_entityStatus = EntityStatus.Waiting;
            m_circleBounds = new Circle();
        }

        public void ApplyDamage(int p_nDamage)
        {
            if (m_nHealth < 0)
                return;

            m_nHealth = Math.Max(0, m_nHealth - p_nDamage);
            if (m_nHealth == 0)
                m_entityStatus = EntityStatus.Destroyed;
        }

        public virtual void OnProjectileHit()
        {
        }

        public virtual void OnPlayerHit()
        {
        }

        public virtual void OnDestroy()
        {
        }

        public virtual void OnDeactivate()
        {
        }

        public virtual void Update(GameTime p_gameTime)
        {
            m_circleBounds.Centre = m_trnPlacement.Translation;
        }

        public abstract void Draw(SpriteBatch p_spriteBatch);

        public abstract EntityType Type { get; }

        public EntityMarker Marker
        {
            get { return m_entityMarker; }
        }

        public Transformation Placement
        {
            get { return m_trnPlacement; }
            set { m_trnPlacement = value; }
        }

        public Vector2 Position
        {
            get { return m_trnPlacement.Translation; }
            set { m_trnPlacement.Translation = value; }
        }

        public float Orientation
        {
            get { return m_trnPlacement.Rotation; }
            set { m_trnPlacement.Rotation = value; }
        }

        public Vector2 Velocity
        {
            get { return m_vecVelocity; }
            set { m_vecVelocity = value; }
        }

        public int Health
        {
            get { return m_nHealth; }
        }

        public int Points
        {
            get { return m_nPoints; }
        }

        public EntityStatus Status
        {
            get { return m_entityStatus; }
            set { m_entityStatus = value; }
        }

        public abstract bool Destructuble { get; }

        public abstract bool Hostile { get; }

        public Circle BoundingCircle
        {
            get { return m_circleBounds; }
        }

        public abstract Geometry Geometry { get; }
    }
}
